TokensController.someProtectedRoute   B
last analyzed

Complexity

Conditions 1

Size

Total Lines 62
Code Lines 53

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 53
dl 0
loc 62
ccs 4
cts 4
cp 1
crap 1
rs 8.5381
c 0
b 0
f 0

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1 8
import { Controller, Post, UseGuards, Req, Param, Get } from '@nestjs/common';
2 8
import { TokensService } from './tokens.service';
3 8
import { TokenResponseDto } from './dto/token-response.dto/token-response.dto';
4 8
import { JwtAuthGuard } from '../auth/guards/jwt-auth.guard';
5 8
import { ApiBearerAuth, ApiHeader, ApiOperation, ApiResponse, ApiTags } from '@nestjs/swagger';
6 8
import { TokenRevocationResponseDto } from './dto/token-revocation-response.dto/TokenRevocationResponseDto';
7 8
import { TokenGuard } from './guards/token.guard';
8
9
@ApiTags('Tokens')
10
@Controller({ path: 'tokens', version: '1' })
11 8
export class TokensController {
12 11
  constructor(private readonly tokensService: TokensService) {}
13
14
  @Post()
15
  @ApiBearerAuth()
16
  @UseGuards(JwtAuthGuard)
17
  @ApiOperation({
18
    summary: 'Create a new token',
19
    description: 'Creates a new token for the authenticated user with specified parameters',
20
  })
21
  @ApiResponse({
22
    status: 201,
23
    description:
24
      'Maximum number of tokens reached. Please consume an existing token before creating a new one',
25
    type: TokenResponseDto,
26
  })
27
  @ApiResponse({
28
    status: 400,
29
    description: 'Bad Request - Invalid token parameters',
30
  })
31
  @ApiResponse({
32
    status: 401,
33
    description: 'Unauthorized - User not authenticated',
34
  })
35 8
  async create(@Req() req): Promise<TokenResponseDto> {
36 1
    const token = await this.tokensService.create(req.user.githubId);
37
38 1
    return {
39
      token: token.id,
40
      remainingUses: token.remainingUses,
41
      expiresAt: token.expiresAt,
42
    };
43
  }
44
45
  @Post(':id/consume')
46
  @ApiOperation({
47
    summary: 'Consume a token',
48
    description: 'Decrements the remaining uses of a token and returns updated token information',
49
  })
50
  @ApiResponse({
51
    status: 201,
52
    description: 'Token consumed successfully',
53
    type: TokenResponseDto,
54
  })
55
  @ApiResponse({
56
    status: 400,
57
    description: 'Bad Request - Token not found or already expired',
58
  })
59
  @ApiResponse({
60
    status: 403,
61
    description: 'Forbidden - Token has no remaining uses',
62
  })
63 8
  async consume(@Param('id') id: string): Promise<TokenResponseDto> {
64 1
    const token = await this.tokensService.consume(id);
65 1
    return {
66
      token: token.id,
67
      remainingUses: token.remainingUses,
68
      expiresAt: token.expiresAt,
69
    };
70
  }
71
72
  @ApiOperation({
73
    summary: 'Protected route example',
74
    description: 'This route requires a valid API token',
75
  })
76
  @ApiHeader({
77
    name: 'x-api-token',
78
    description: 'API Token for route access',
79
    required: true,
80
    schema: { type: 'string' },
81
  })
82
  @ApiResponse({
83
    status: 200,
84
    description: 'Route accessed successfully',
85
    schema: {
86
      type: 'object',
87
      properties: {
88
        message: { type: 'string', example: 'Access granted' },
89
      },
90
    },
91
  })
92
  @ApiResponse({
93
    status: 401,
94
    description: 'Unauthorized - Invalid or missing token',
95
    schema: {
96
      type: 'object',
97
      properties: {
98
        message: { type: 'string', example: 'Token is required' },
99
        statusCode: { type: 'number', example: 401 },
100
      },
101
    },
102
  })
103
  @UseGuards(TokenGuard)
104
  @Get('protected-route')
105 8
  async someProtectedRoute() {
106 1
    const insights = [
107
      "Believe you can and you're halfway there.",
108
      'The only way to do great work is to love what you do.',
109
      'Success is not the key to happiness. Happiness is the key to success.',
110
      "Your time is limited, don't waste it living someone else's life.",
111
      'The best way to predict the future is to invent it.',
112
      "Don't watch the clock; do what it does. Keep going.",
113
      'Keep your face always toward the sunshine—and shadows will fall behind you.',
114
      'The only limit to our realization of tomorrow is our doubts of today.',
115
      'The future belongs to those who believe in the beauty of their dreams.',
116
      'It does not matter how slowly you go as long as you do not stop.',
117
      'Act as if what you do makes a difference. It does.',
118
      'Success usually comes to those who are too busy to be looking for it.',
119
      "Don't be afraid to give up the good to go for the great.",
120
      'I find that the harder I work, the more luck I seem to have.',
121
      'Success is not in what you have, but who you are.',
122
      'The way to get started is to quit talking and begin doing.',
123
      "Don't let yesterday take up too much of today.",
124
      "You learn more from failure than from success. Don't let it stop you. Failure builds character.",
125
      "It's not whether you get knocked down, it's whether you get up.",
126
      "If you are working on something that you really care about, you don't have to be pushed. The vision pulls you.",
127
    ];
128
129 1
    const randomInsight = insights[Math.floor(Math.random() * insights.length)];
130
131 1
    return {
132
      message: `Access granted! Woho, you have just consumed 1 token! Here's a life insight for you: ${randomInsight}`,
133
    };
134
  }
135
136
  @Get(':id')
137
  @ApiOperation({
138
    summary: 'Get token information',
139
    description: 'Retrieves detailed information about a specific token',
140
  })
141
  @ApiResponse({
142
    status: 200,
143
    description: 'Token information retrieved successfully',
144
    type: TokenResponseDto,
145
  })
146
  @ApiResponse({
147
    status: 404,
148
    description: 'Token not found',
149
  })
150 8
  async findOne(@Param('id') id: string): Promise<TokenResponseDto> {
151 1
    const token = await this.tokensService.findOne(id);
152 1
    return {
153
      token: token.id,
154
      remainingUses: token.remainingUses,
155
      expiresAt: token.expiresAt,
156
    };
157
  }
158
159
  @Post('/revoke/user')
160
  @ApiBearerAuth()
161
  @UseGuards(JwtAuthGuard)
162
  @ApiOperation({
163
    summary: 'Revoke all tokens for a user',
164
    description: 'Revokes all tokens for a specific user',
165
  })
166
  @ApiResponse({
167
    status: 200,
168
    description: 'Tokens revoked successfully',
169
    type: TokenRevocationResponseDto,
170
  })
171
  @ApiResponse({
172
    status: 401,
173
    description: 'Unauthorized - User not authenticated',
174
  })
175 8
  async revokeAllForUser(@Req() req): Promise<TokenRevocationResponseDto> {
176 1
    const result = await this.tokensService.revokeAllForUser(req.user.githubId);
177 1
    return {
178
      success: true,
179
      message: 'All tokens have been revoked successfully',
180
      revokedCount: result.affected, // If you want to include this information
181
    };
182
  }
183
}
184